
/*
 *  
 *
 *  Copyright (C) Microsoft Corporation.  All rights reserved
 *
 *  
 */


using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Collections.Specialized;
using Microsoft.Crm.DataBindining;

namespace CRMScenarios
{

    /// <summary>
    /// The three option in which we want to refresh the pane.
    /// - The inital one when you open the document.
    /// - On a click from toolbar.
    /// - From the link provided at the bottom.
    /// </summary>
    public enum RefreshOption
    {
        Initial,
        FromTB,
        FromLink,
    }

    /// <summary>
    /// The five states in whihc the pane can be in.
    /// - Something not likely happened.
    /// - Something really wrong occured.
    /// - Busy doing the work.
    /// - Just relaxing!! Free
    /// - Successfully did the job.  :)
    /// </summary>
    public enum InfoOptions
    {
        Warning,
        Error,
        Busy,
        Free,
        Success,
    }

    /// <summary>
    /// The form which is the base one for both the attach doc and insertfield panes. 
    /// This contains the common routines. And some of the controls too. 
    /// Controls are just declared here. The actual definition will be there in the 
    /// corresponding files. Would be better to move the controls from this file 
    /// to the respective ones, so that the designer can show it witout any trouble.
    /// (sands)
    /// </summary>
    public partial class BaseUserControl : UserControl
    {
        protected int xPadding = 6;
        protected BusinessEntity thisRecord = null;
        protected BusinessEntity selectedRelatedRecord = null;
        protected BusinessEntityCollection currentRelatedBec = null;
        protected AutoCompleteStringCollection TextBoxCacheSource = null;
        protected object Application = null;
        protected object ActiveOne = null;
        protected InfoOptions InfoStatus;
        protected Label lnklblWarning;
        protected PictureBox picWarning;
        protected PictureBox picHelp;
        protected Panel panelOtherTask;
        protected DataGridView listViewOfRelatedRecordDetails;
        protected DataGridViewCellEventArgs mouseLocation;
        protected Button btnLookup;
        protected ComboBox comboBoxEntityTypeLookFor;
        protected ComboBox cmBoxRelated;
        protected TextBox textBoxLookForText;
        protected Button buttonGoSearch;
        protected ToolTip toolTipForTextBox;
        protected ToolTip toolTipForPicBtnBack;
        protected ToolTip toolTipForPicBtnForward;
        protected Label lblNoRecordFound;
        protected PictureBox firstPagePic;
        protected PictureBox previousPagePic;
        protected PictureBox nextPagePic;
        protected PictureBox PicBtnForward;
        protected PictureBox PicBtnBack;   
        protected Label lblPageNum;
        protected Label lblNoRelRecords;
        protected CheckBox CBoxSelectAllRelRec = null;
        protected string[][] MainComboMapping = null;
        protected string[][] RelatedComboMapping = null;
        protected PageInfo pageInfo = null;
        protected bool ChangingLookupComboProgrammatically = false;
        protected bool CBoxSelectAllRelRecChangedProgrammatically = false;
        protected bool RelatedGridSelectionChangeProgramattically = false;
        protected bool UsingBackForthButton = false;
        protected BackForthInfo GoBackAndForth = new BackForthInfo();
        protected Process HelpProcess = null;

        /// <summary>
        /// We might need to disable all the controls on the action pane, with some 
        /// exceptions.
        /// </summary>
        protected void DisableAllControls()
        {
            foreach (Control ctrl in this.Controls)
            {
                if ((ctrl is Label) || (ctrl is LinkLabel))
                {
                    continue;
                }
                if ((ctrl is ComboBox) || (ctrl is TextBox))
                {
                    ctrl.BackColor = System.Drawing.SystemColors.Window;
                }
                ctrl.Enabled = false;
            }
            panelOtherTask.Enabled  = true;
            picHelp.Enabled         = true;
            picWarning.Enabled      = true;
            DisablePaging();
        }

        /// <summary>
        /// Okay. We just want to know the index of element "el" in the array "arr"
        /// Pretty straight forward.
        /// </summary>
        /// <param name="arr"></param>
        /// <param name="el"></param>
        /// <returns></returns>
        protected int index(ref string[] arr, string el)
        {
            if (arr == null)
            {
                return -1;
            }
            for (int i = 0; i < arr.Length; i++)
            {
                if (arr[i] == el)
                {
                    return i;
                }
            }
            return -1;
        }

        /// <summary>
        /// Take the displayed value of the entity name from the combo box. 
        /// Find the index of it. And look at the schema name array at that index 
        /// to get the schema name for the enityt.
        /// </summary>
        /// <returns></returns>
        protected string MainEntityName()
        {
            int iIndex = index(ref MainComboMapping[0], (string)this.comboBoxEntityTypeLookFor.SelectedItem);
            return ((iIndex != -1) ? (MainComboMapping[1][iIndex]) : (string.Empty));
        }
        
        /// <summary>
        /// Take the displayed value of the related entity name from the combo box. 
        /// Find the index of it. And look at the schema name array at that index 
        /// to get the schema name for the related enityt.
        /// </summary>
        /// <returns></returns>
        protected string RelatedEntityName()
        {
            int iIndex = index(ref RelatedComboMapping[0], (string)this.cmBoxRelated.SelectedItem);
            return ((iIndex != -1) ? (RelatedComboMapping[1][iIndex]) : (string.Empty));
        }

        /// <summary>
        /// Virtual function.
        /// 
        /// </summary>
        /// <param name="application"></param>
        /// <param name="activeOne"></param>
        public virtual void initializeControls(object application, object activeOne)
        { }

        /// <summary>
        /// Show the message in "error" 
        /// with the proper status symbol corresponding to "status" 
        /// </summary>
        /// <param name="error"></param>
        /// <param name="status"></param>
        public void FlagErrorOrWarning(string error, InfoOptions status)
        {
            lnklblWarning.Text = error;
            lnklblWarning.Visible = true;
            picWarning.Enabled = picWarning.Visible = true;
            InfoStatus = ((error == string.Empty) ? (InfoOptions.Free) : (status));
            switch (status)
            {
                case InfoOptions.Busy:
                    picWarning.Image = global::CRMScenarios.Resources.progress;
                    break; 
                case InfoOptions.Error:
                    picWarning.Image = global::CRMScenarios.Resources.error;
                    break;
                case InfoOptions.Free:
                    picWarning.Image = null;
                    lnklblWarning.Visible = false;
                    picWarning.Enabled = picWarning.Visible =  false;
                    break;
                case InfoOptions.Warning:
                    picWarning.Image = global::CRMScenarios.Resources.warning;
                    break;
                case InfoOptions.Success:
                    picWarning.Image = global::CRMScenarios.Resources.success;
                    break;
                default:
                    picWarning.Image = null;
                    lnklblWarning.Visible = false;
                    picWarning.Enabled = picWarning.Visible = false;
                    break;
            }
            Refresh();
        }

        /// <summary>
        /// Make the illusion of busy by changing the cursor.
        /// </summary>
        /// <param name="Message"></param>
        protected void MakeItLookBusy(string Message)
        {
            this.Cursor = Cursors.WaitCursor;
            FlagErrorOrWarning(((Message == null) ? (string.Empty) : (Message)), InfoOptions.Busy);
            Refresh();
        }

        /// <summary>
        /// Remove the busy messages and symbols and make the pane free for next job.
        /// </summary>
        protected void NotBusyAnyMore()
        {
            this.Cursor = Cursors.Default;
            if ((lnklblWarning.Text == string.Empty) || (InfoStatus == InfoOptions.Busy))
            {
                InfoStatus = InfoOptions.Free;
                lnklblWarning.Text = string.Empty;
                lnklblWarning.Visible = false;
                picWarning.Image = null;
                Refresh();
            }
        }


        /// <summary>
        /// Get the focus on click of the mouse.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void BaseUserControl_MouseDown(object sender, MouseEventArgs e)
        {
            this.Focus();
        }
        
        /// <summary>
        /// Initialization of controls, attaching the event handlers.
        /// </summary>
        /// <param name="application"></param>
        /// <param name="activeOne"></param>
        public void InitializeControls(object application, object activeOne)
        {
            FlagErrorOrWarning(global::CRMScenarios.Resources.Initializing, InfoOptions.Busy);
            DisableAllControls();
            initializeControls(application, activeOne);            

            this.MouseDown += new MouseEventHandler(BaseUserControl_MouseDown);

            this.firstPagePic.Image = global::CRMScenarios.Resources.frew;
            this.previousPagePic.Image = global::CRMScenarios.Resources.rew;
            this.nextPagePic.Image = global::CRMScenarios.Resources.fwd;


            FlagErrorOrWarning(string.Empty, InfoOptions.Free);
            pageInfo = new PageInfo();
            DisablePaging();


            this.PicBtnBack.Image = global::CRMScenarios.Resources.back;
            this.PicBtnForward.Image = global::CRMScenarios.Resources.forth;
            this.PicBtnBack.Enabled = GoBackAndForth.CanGoBackward();
            this.PicBtnForward.Enabled = GoBackAndForth.CanGoFroward();


            toolTipForPicBtnBack = new ToolTip();
            toolTipForPicBtnBack.AutoPopDelay = 5000;
            toolTipForPicBtnBack.InitialDelay = 100;
            toolTipForPicBtnBack.ReshowDelay = 500;
            toolTipForPicBtnBack.SetToolTip(PicBtnBack, global::CRMScenarios.Resources.PreviousRecord);

            toolTipForPicBtnForward = new ToolTip();
            toolTipForPicBtnForward.AutoPopDelay = 5000;
            toolTipForPicBtnForward.InitialDelay = 100;
            toolTipForPicBtnForward.ReshowDelay = 500;
            toolTipForPicBtnForward.SetToolTip(PicBtnForward, global::CRMScenarios.Resources.NextRecord);

            // NOW ALL THE INIT IS OVER - I CAN GIVE FOCUS TO THE COMBO!!
            this.comboBoxEntityTypeLookFor.Focus();
        }
        
        /// <summary>
        /// Read the key from registry and refresh the metadata if needed.
        /// </summary>
        protected void RefreshMetaDataIfNeeded()
        {
            if (CacheManager.GetRefreshMDCacheBit() == true)
            {
                FlagErrorOrWarning(global::CRMScenarios.Resources.RefreshingMetadataMsg, InfoOptions.Busy);
                DisableAllControls();
                CacheManager.SetRefreshMDCacheBit(false);
                DisableAllControls();
                initializeControls(Application, ActiveOne);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Url"></param>
        protected void OpenPage(string Url)
        {
            if ((Url == null) || (Url == string.Empty))
            {
                return;
            }
            try
            {
                System.Diagnostics.Process.Start("iexplore", Url);
            }
            catch (Exception)
            { }
        }

        /// <summary>
        /// 
        /// </summary>
        public BaseUserControl()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BaseUserControl_Load(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// Populate the strings in a cmBox
        /// </summary>
        /// <param name="cmBox"></param>
        /// <param name="strings"></param>
        protected void populateCombo(ref ComboBox cmBox, StringCollection strings)
        {
            if ((cmBox == null) || (strings == null))
            {
                return;
            }

            foreach (string s in strings)
            {
                cmBox.Items.Add((object)s);
            }
        }

        /// <summary>
        /// Populate the strings in a cmBox
        /// </summary>
        /// <param name="cmBox"></param>
        /// <param name="strings"></param>
        protected void populateCombo(ref ComboBox cmBox, string[] strings)
        {
            if ((cmBox == null) || (strings == null))
            {
                return;
            }

            foreach (string s in strings)
            {
                cmBox.Items.Add((object)s);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="formXmlParsed"></param>
        public virtual void FillDetailsInListView(BusinessEntity entity, string[][] formXmlParsed)
        {
            return;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="entityType"></param>
        public virtual void getDetailsOfTheEntityAndDisplay(BusinessEntity entity, string entityType)
        {
            return;
        }

        /// <summary>
        /// Given the entity type and necessary columnnames, get the details and fill 
        /// the datagridview from the business entity collection.
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="columnNames"></param>
        protected void FillRelatedRecordsView(string entityType, string[] columnNames)
        {
            this.listViewOfRelatedRecordDetails.Columns.Clear();
            lblNoRelRecords.Visible = lblNoRelRecords.Enabled = false;
            if (CBoxSelectAllRelRec != null) 
            { 
                CBoxSelectAllRelRec.Visible = CBoxSelectAllRelRec.Enabled = false;
            }

            if ((currentRelatedBec == null) || (columnNames == null)) 
            {
                FlagErrorOrWarning(global::CRMScenarios.Resources.ErrorInSearching, InfoOptions.Error);
                return;
            }
            
            listViewOfRelatedRecordDetails.AutoGenerateColumns = true;
            IDictionary nameToTypeMap = CrmConnector.GetNameToTypeMapping(entityType, columnNames);
            listViewOfRelatedRecordDetails.DataSource = UniversalEntity.CreateFromDynamicEntityCollection(currentRelatedBec, ref nameToTypeMap);
            string [] DataBndColumnNames = CrmConnector.GetDataBoundAttribNames(entityType, columnNames);
            StringCollection columNameCollection = CrmConnector.ArrayToCollection(DataBndColumnNames);
            columNameCollection.Remove(CrmConnector.GetEntityMetaData(entityType).PrimaryKey);

            foreach (DataGridViewColumn s in this.listViewOfRelatedRecordDetails.Columns)
            {
                if (s != null)
                {
                    s.Visible = false;
                }
            }

            int TotalColumnWidth = 0;
            foreach (string lookUpCol in columNameCollection)
            {
                string dispName = CrmConnector.GetDisplayNameOfAttribute(entityType, lookUpCol);
                string displayName = ((dispName == null) || (dispName == string.Empty)) ? (lookUpCol) : (dispName);
                if (listViewOfRelatedRecordDetails.Columns.Contains(lookUpCol))
                {
                    listViewOfRelatedRecordDetails.Columns[lookUpCol].HeaderText = displayName;
                }
                else
                {
                    listViewOfRelatedRecordDetails.Columns.Add(lookUpCol, displayName);
                }
                listViewOfRelatedRecordDetails.Columns[lookUpCol].DisplayIndex = columNameCollection.IndexOf(lookUpCol);
                listViewOfRelatedRecordDetails.Columns[lookUpCol].Visible = true;
                listViewOfRelatedRecordDetails.Columns[lookUpCol].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
                TotalColumnWidth += listViewOfRelatedRecordDetails.Columns[lookUpCol].Width;
            }

            if (TotalColumnWidth < listViewOfRelatedRecordDetails.Width)
            {
                foreach (string lookUpCol in columNameCollection)
                {
                    listViewOfRelatedRecordDetails.Columns[lookUpCol].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
                }
            }

            EnablePaging();

            if (this.listViewOfRelatedRecordDetails.Rows.Count == 0)
            {
                FlagErrorOrWarning(global::CRMScenarios.Resources.NoRelatedRecordsPresent, InfoOptions.Warning);
                lblNoRelRecords.Enabled = true;
                lblNoRelRecords.Visible = true;
                return;
            }

            FlagErrorOrWarning(string.Empty, InfoOptions.Free);
            this.listViewOfRelatedRecordDetails.Enabled = true;
            AddContextMenu();
            if (CBoxSelectAllRelRec != null)
            {
                CBoxSelectAllRelRec.Checked = false;
                CBoxSelectAllRelRec.Visible = CBoxSelectAllRelRec.Enabled = true;
            }
        }
        
        /// <summary>
        /// 
        /// </summary>
        protected virtual void AddContextMenu()
        { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="be"></param>
        public virtual void ActivateAttachAsNeeded(string entityType, ref BusinessEntity be)
        { }

        /// <summary>
        ///
        /// </summary>
        public virtual void DisableControlsWhileLookUp()
        { }

        /// <summary>
        /// Create a new lookup window and pass the proper patameters needed.
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="searchPattern"></param>
        protected void CreateAndShowANewLookUpDlg(string entity, string searchPattern)
        {
            MakeItLookBusy(global::CRMScenarios.Resources.NonSingleRecords);
            LookUpDialogBox lookupDialogBox = null;
            lookupDialogBox = new LookUpDialogBox();
            lookupDialogBox.InitializeLookUpDialogBox(entity, searchPattern, this);
            lookupDialogBox.TopMost = OfficeApi.IsOutLook(ActiveOne);
            lookupDialogBox.ShowDialog();
            NotBusyAnyMore();
            OfficeApi.ActivateWindow(ActiveOne);
        }


        /// <summary>
        /// The pane has to be refreshed with the details of the enityt referred. 
        /// How to refresh specified in the "refresh" parameter.
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="txtBox"></param>
        /// <param name="entity"></param>
        /// <param name="refresh"></param>
        public void RefreshAccordingToTheOtherPane(string entityType, string txtBox, ref BusinessEntity entity, RefreshOption refresh)
        {
            if (refresh == RefreshOption.Initial)
            {
                return;
            }

            if (refresh == RefreshOption.FromTB)
            {
                DisableAllControls();
                initializeControls(Application, ActiveOne);
                NotBusyAnyMore();
            }

            getDetailsOfTheEntityAndDisplay(entity, entityType);
        }

        /// <summary>
        /// Change the page according to the information provided in the pInfo.
        /// </summary>
        /// <param name="pInfo"></param>
        protected void PageChange(PagingInfo pInfo)
        {
            string entityType = RelatedEntityName();
            string[] columnNames = null;
            currentRelatedBec = CrmConnector.GetRelatedEntites(thisRecord, MainEntityName(), RelatedEntityName(), pInfo);
            columnNames = CrmConnector.GetQkColumnsIfNoLookUpAvailable(entityType);
            if (currentRelatedBec == null)
            {
                FlagErrorOrWarning(global::CRMScenarios.Resources.ErrorInSearching, InfoOptions.Error);
                return;
            }
            //if (columnNames == null)
            //{
            //    FlagErrorOrWarning(global::CRMScenarios.Resources.ErrorInSearching, InfoOptions.Error);
            //    return;
            //}
            FillRelatedRecordsView(entityType, columnNames);
        }

        /// <summary>
        /// Have a look at the present situation (bec count, page number etc)
        /// and decide which all buttons need to be enabled/disabled.
        /// </summary>
        protected void EnablePaging()
        {
            int currentPage = pageInfo.CurrentPage();
            if ((currentRelatedBec.BusinessEntities.Length == 0) && (currentPage == 0))
            {
                DisablePaging();
                return;
            }

            int currentCount = currentRelatedBec.BusinessEntities.Length;
            firstPagePic.Enabled = previousPagePic.Enabled = !(currentPage == 1);
            nextPagePic.Enabled = !(currentCount < pageInfo.MaxRecCountInGrid);

            firstPagePic.Visible = true;
            previousPagePic.Visible = true;
            nextPagePic.Visible = true;
            lblPageNum.Text = global::CRMScenarios.Resources.LabelPage + currentPage.ToString();
            lblPageNum.Visible = lblPageNum.Enabled = true;
        }

        /// <summary>
        /// 
        /// </summary>
        protected void DisablePaging()
        {
            firstPagePic.Enabled    = firstPagePic.Visible      = false;
            previousPagePic.Enabled = previousPagePic.Visible   = false;
            nextPagePic.Enabled     = nextPagePic.Visible       = false;
            lblPageNum.Enabled      = lblPageNum.Visible        = false;
        }

        /// <summary>
        /// Get the stored search strings from registry and update the textbox autofill strings.
        /// </summary>
        protected void UpDateTxtBoxCache()
        {
            StringCollection textCacheSource = CacheManager.getUpdatedCache(textBoxLookForText.Text, MainEntityName());
            this.textBoxLookForText.AutoCompleteCustomSource = null;
            if (textCacheSource != null)
            {
                this.TextBoxCacheSource.Clear();
                foreach (string s in textCacheSource)
                {
                    this.TextBoxCacheSource.Add(s);
                }
            }
            this.textBoxLookForText.AutoCompleteCustomSource = TextBoxCacheSource;
        }


        /// <summary>
        /// Move back or forth to the record specifeied by guid. 
        /// Also, enable/disable the buttons if movement is not allowed.
        /// </summary>
        /// <param name="guid"></param>
        /// <param name="eType"></param>
        protected void MoveBackAndForth(Guid guid, string eType)
        {
            BusinessEntity be = CrmConnector.GetAllDetailsOfThisEntity(guid, eType);
            if (be == null)
            {
                FlagErrorOrWarning(global::CRMScenarios.Resources.ErrorInSearching, InfoOptions.Error);
                return;
            }
            UsingBackForthButton = true;
            getDetailsOfTheEntityAndDisplay(be, eType);
            UsingBackForthButton = false;
            PicBtnBack.Enabled = GoBackAndForth.CanGoBackward();
            PicBtnForward.Enabled = GoBackAndForth.CanGoFroward();
        }

        /// <summary>
        /// Open the help file in a process.
        /// If already the process is already open. Then surface it on top.
        /// </summary>
        /// <param name="section"></param>
        protected  void GiveHelpOrTips(string section)
        {
            string installLocation = CacheManager.GetInstallPath(string.Empty);

            if (HelpProcess != null)
            {
                if (!HelpProcess.HasExited)
                {
                    HelpProcess.Kill();
                }
                HelpProcess = null;
            }

            if ((installLocation == null) || (installLocation == string.Empty))
            {
                // corrupted
            }
            try
            {
                string option = (((section == null) || (section.Length == 0)) ? (string.Empty) : ("::/" + section + "#"));
                HelpProcess = Process.Start("hh", installLocation + @"\MSCRMAddin.chm" + option);
            }
            catch (Exception)// helpError)
            {
                // installation seems to be corrupted.
            }
        }
    }
}
